"""
四川麻将规则判断模块
"""
from typing import List, Tuple, Set
from sichuanmajiang.engine.cards import Tile, Suit, SuitTile, TileSet


def is_legal_hand(tiles: List[Tile]) -> bool:
    """检查手牌数量是否合法"""
    return len(tiles) % 3 == 2


def group_tiles_by_value_and_suit(tiles: List[Tile]) -> dict:
    """将牌按花色和数值分组"""
    groups = {}
    for tile in tiles:
        key = (tile.suit, tile.value)
        if key not in groups:
            groups[key] = 0
        groups[key] += 1
    return groups


def check_hu(tiles: List[Tile]) -> bool:
    """
    检查是否可以胡牌
    四川麻将胡牌规则：四组刻子或顺子 + 一对将牌
    """
    # 首先检查牌的数量
    if not is_legal_hand(tiles):
        return False
    
    # 按花色和数值排序
    sorted_tiles = sorted(tiles, key=lambda t: (t.suit.value, t.value))
    
    # 尝试寻找将牌
    return check_hu_with_jiang(sorted_tiles)


def check_hu_with_jiang(tiles: List[Tile]) -> bool:
    """尝试寻找将牌并检查剩余牌是否可以组成刻子或顺子"""
    # 统计每种牌的数量
    count_map = group_tiles_by_value_and_suit(tiles)
    
    # 尝试每一种牌作为将牌
    for key, count in count_map.items():
        if count >= 2:
            # 创建临时计数map
            temp_map = count_map.copy()
            temp_map[key] -= 2
            
            # 检查剩余牌是否可以组成副子
            if check_fuzi(temp_map):
                return True
    
    return False


def check_fuzi(count_map: dict) -> bool:
    """检查是否所有牌都可以组成刻子或顺子"""
    # 深拷贝计数map
    temp_map = count_map.copy()
    
    # 处理每种花色
    suits = {key[0] for key in temp_map.keys()}
    
    for suit in suits:
        # 获取该花色的所有牌值
        suit_values = [key[1] for key in temp_map.keys() if key[0] == suit and temp_map[key] > 0]
        suit_values.sort()
        
        # 所有牌都是序数牌，可以组成刻子或顺子
        i = 0
        while i < len(suit_values):
            value = suit_values[i]
            key = (suit, value)
            count = temp_map[key]
            
            # 尝试组成刻子
            if count >= 3:
                temp_map[key] -= 3
                if temp_map[key] == 0:
                    i += 1
            # 尝试组成顺子
            elif count > 0 and value + 2 <= 9:
                key1 = (suit, value + 1)
                key2 = (suit, value + 2)
                
                if key1 in temp_map and key2 in temp_map and temp_map[key1] > 0 and temp_map[key2] > 0:
                    temp_map[key] -= 1
                    temp_map[key1] -= 1
                    temp_map[key2] -= 1
                    
                    # 如果当前牌用完了，移动到下一个
                    if temp_map[key] == 0:
                        i += 1
                else:
                    return False
            elif count > 0:
                return False
            else:
                i += 1
    
    return True


def check_peng(tile: Tile, player_hand: List[Tile]) -> bool:
    """检查是否可以碰牌"""
    return player_hand.count(tile) >= 2


def check_gang(tile: Tile, player_hand: List[Tile], exposed_tiles: List[List[Tile]] = None) -> Tuple[bool, str]:
    """
    检查是否可以杠牌
    返回 (是否可以杠, 杠的类型)
    杠的类型: "暗杠", "明杠", "加杠"
    """
    hand_count = player_hand.count(tile)
    
    # 检查暗杠
    if hand_count == 4:
        return True, "暗杠"
    elif hand_count == 3:
        return True, "明杠"
    
    # 检查加杠（已有碰的牌）
    if exposed_tiles:
        for exposed_group in exposed_tiles:
            if len(exposed_group) == 3 and all(t == tile for t in exposed_group) and hand_count == 1:
                return True, "加杠"
    
    return False, ""


def check_chi(tile: Tile, player_hand: List[Tile]) -> List[List[Tile]]:
    """
    检查是否可以吃牌
    返回可以组成的顺子列表
    """
    # 所有牌都是序数牌，可以吃
    
    possible_chis = []
    value = tile.value
    suit = tile.suit
    
    # 统计手牌中该花色的牌
    suit_tiles = [t.value for t in player_hand if t.suit == suit]
    
    # 尝试组成顺子的三种情况
    # 1. [tile-2, tile-1, tile]
    if value - 2 >= 1 and value - 1 in suit_tiles and value - 2 in suit_tiles:
        possible_chis.append([
            SuitTile(suit, value - 2),
            SuitTile(suit, value - 1),
            tile
        ])
    
    # 2. [tile-1, tile, tile+1]
    if value - 1 >= 1 and value + 1 <= 9 and value - 1 in suit_tiles and value + 1 in suit_tiles:
        possible_chis.append([
            SuitTile(suit, value - 1),
            tile,
            SuitTile(suit, value + 1)
        ])
    
    # 3. [tile, tile+1, tile+2]
    if value + 2 <= 9 and value + 1 in suit_tiles and value + 2 in suit_tiles:
        possible_chis.append([
            tile,
            SuitTile(suit, value + 1),
            SuitTile(suit, value + 2)
        ])
    
    return possible_chis


def calculate_score(hu_type: str, fan_count: int, base_score: int = 1) -> int:
    """
    计算胡牌分数
    hu_type: 胡牌类型（如"自摸", "点炮", "杠上花", "抢杠胡"等）
    fan_count: 番数
    base_score: 基础分数
    """
    # 基础倍数计算
    multiplier = 2 ** fan_count
    
    # 根据胡牌类型调整倍数
    if hu_type == "自摸":
        # 自摸时三家都要支付
        return base_score * multiplier * 3
    elif hu_type == "点炮":
        # 点炮时只有点炮者支付
        return base_score * multiplier
    elif hu_type == "杠上花":
        # 杠上花额外加倍数
        return base_score * multiplier * 2
    elif hu_type == "抢杠胡":
        # 抢杠胡通常倍数更高
        return base_score * multiplier * 2
    
    return base_score * multiplier


def calculate_fan(tiles: List[Tile], exposed_tiles: List[List[Tile]], win_tile: Tile = None) -> int:
    """
    计算番数
    这是一个简化版本，实际四川麻将番数规则很复杂
    """
    fan = 0
    
    # 基础胡牌（1番）
    fan += 1
    
    # 检查是否是碰碰胡（全是刻子）
    if is_pengpeng_hu(tiles, exposed_tiles):
        fan += 1
    
    # 检查是否是清一色
    if is_pure_suit(tiles, exposed_tiles):
        fan += 4
    elif is_mixed_suit(tiles, exposed_tiles):
        fan += 2
    
    # 检查是否是七对
    if is_seven_pairs(tiles):
        fan += 2
    
    # 检查是否是将对
    if is_jiangdui(tiles):
        fan += 2
    
    # 更多番型可以在这里添加
    
    return fan


def is_pengpeng_hu(tiles: List[Tile], exposed_tiles: List[List[Tile]]) -> bool:
    """检查是否是碰碰胡"""
    # 所有的副子都是刻子
    all_tiles = tiles.copy()
    for group in exposed_tiles:
        all_tiles.extend(group)
    
    count_map = group_tiles_by_value_and_suit(all_tiles)
    
    # 找出将牌
    jiang_found = False
    for key, count in count_map.items():
        if count % 3 == 2:
            if jiang_found:
                return False
            jiang_found = True
        elif count % 3 != 0:
            return False
    
    return jiang_found


def is_pure_suit(tiles: List[Tile], exposed_tiles: List[List[Tile]]) -> bool:
    """检查是否是清一色"""
    all_tiles = tiles.copy()
    for group in exposed_tiles:
        all_tiles.extend(group)
    
    suits = {tile.suit for tile in all_tiles}
    return len(suits) == 1


def is_mixed_suit(tiles: List[Tile], exposed_tiles: List[List[Tile]]) -> bool:
    """检查是否是混一色
    在四川麻将中，混一色是指手牌和副露牌只有一种花色（筒、条、万中的一种）
    """
    all_tiles = tiles.copy()
    for group in exposed_tiles:
        all_tiles.extend(group)
    
    suits = {tile.suit for tile in all_tiles}
    return len(suits) == 1


def is_seven_pairs(tiles: List[Tile]) -> bool:
    """检查是否是七对"""
    if len(tiles) != 14:
        return False
    
    count_map = group_tiles_by_value_and_suit(tiles)
    
    # 七对需要7个对子
    return len(count_map) == 7 and all(count == 2 for count in count_map.values())


def is_jiangdui(tiles: List[Tile]) -> bool:
    """检查是否是将对（全是对子，且全是2、5、8）"""
    if not is_seven_pairs(tiles):
        return False
    
    jiang_values = {2, 5, 8}
    
    for tile in tiles:
        if tile.value not in jiang_values:
            return False
    
    return True